import java.util.ArrayList;
public class Cell {
	private boolean visited = false; //if cell was visited by the DFS
	private boolean start = false; //cell is start cell
	private boolean end = false; //cell is end cell
	private ArrayList<Cell> neighbors; //neighbors of this cell
	public boolean northWall = true; //north wall exists
	public boolean eastWall = true; //east wall exists
	public boolean southWall = true; //south wall exists
	public boolean westWall = true; //west wall exists
	private int x; //x coordinate of this cell in the maze
	private int y; //y coordinate of this cell in the maze
	public boolean ispath = false;
	private int walls;

	public boolean wasVisted(){
		if (visited) return true;
		return false;
	}
	//constructor
	public Cell(int x, int y) { 
		this.x = x;
		this.y = y;
	}
	

	public boolean isEndtoPath(){
		int count=0;
		if(northWall)
			count++;
		if(southWall)
			count++;
		if(westWall)
			count++;
		if(eastWall)
			count++;
		if (count >=  3) return true;
		else return false;
	}
	
	//get wall for each cell
	public int cellWallsCount(){
		if(northWall) 
			walls++;
		if(eastWall) 
			walls++;
		if(southWall) 
			walls++;
		if(westWall) 
			walls++;
		return walls;
	}
	
	//set this Cell as visited
	public void setVisited() {
		this.visited = true;
	}
	
	//reset Visit
	public void resetVisit(){
		this.visited = false;
	}

	//is this the end cell?
	public boolean isEnd() {
		return end;
	}
	
	//is this the start cell?
	public boolean isStart() {
		return start;
	}

	//set this cell as start
	public void setStart() {
		this.start = true;
	}

	//set this cell as end
	public void setEnd() {
		this.end = true;
	}
	
	//get x coordinate
	public int getX(){
		return x;
	}
	
	//get y coordinate
	public int getY(){
		return y;
	}

	//set the neighbors array
	public void setNeighbors(ArrayList<Cell> n) {
		this.neighbors = n;
	}

	//are there unvisited neighbors?
	public boolean isDeadEnd() {
		for (Cell c : neighbors) {
			if (!c.visited)
				return false;
		}
		return true;
	}
	


	//get unvisited neighbors
	private ArrayList<Cell> availableNeighbors() {
		ArrayList<Cell> list = new ArrayList<Cell>();
		for (Cell c : neighbors) {
			if (!c.visited)
				list.add(c);
		}
		return list;
	}
	

	
	public Cell pickNeighbor(Sketch s){
		for (Cell c : neighbors) {
			if (x == c.x) {
				if ((y < c.y) && !southWall  &&!c.visited) {
					return c;
				}
				if ((y > c.y) && !northWall &&!c.visited) {
					return c;
				}
			}else if (y == c.y) {
				if ((x < c.x) && !eastWall &&!c.visited) {
					return c;
				}
				if ((x > c.x) && !westWall &&!c.visited) {
					return c;
				}
			}
		}
		return null;
	}
	
	public int pickGeneNeighbor(){
		ArrayList<Integer> dirs = new ArrayList<Integer>();
		for (Cell c : neighbors) {
			if (x == c.x) {
				if ((y < c.y) && !southWall && !c.isEndtoPath()) {
					//return 3;
					dirs.add(3);
				}
				if ((y > c.y) && !northWall && !c.isEndtoPath()) {
					//return 1;
					dirs.add(1);
				}
				
				int size = dirs.size();
				if(size > 0){
					int item = Rand.r.nextInt(size); 
					int i = 0;
					for(Object obj : dirs){
					    if (i == item)
					        return (Integer) obj;
					    i++;
					}
				}
			}else if (y == c.y) {
				if ((x < c.x) && !eastWall && !c.isEndtoPath()) {
					//return 2;
					dirs.add(2);
				}
				if ((x > c.x) && !westWall && !c.isEndtoPath()) {
					//return 4;
					dirs.add(4);
				}
				int size = dirs.size();
				if(size > 0){
					int item = Rand.r.nextInt(size); 
					int i = 0;
					for(Object obj : dirs){
					    if (i == item)
					        return (Integer) obj;
					    i++;
					}
				}
			}
		}
		return 0;
	}
	
	//pick a random unvisited neighbor
	public Cell randomNeighbor() {
		return (Cell) Rand.pickRandom(availableNeighbors());
	}



	//break walls between this cell and given cell
	public void breakWall(Cell n) {
		if (x == n.x) {
			if (y < n.y) {
				southWall = false;
				n.northWall = false;
			}
			if (y > n.y) {
				northWall = false;
				n.southWall = false;
			}
		} else if (y == n.y) {
			if (x < n.x) {
				eastWall = false;
				n.westWall = false;
			}
			if (x > n.x) {
				westWall = false;
				n.eastWall = false;
			}
		}
	}
	
	//draw this cell to given Sketch
	public void drawCell(Sketch s) {
		//calculate origin (top-left corner) of this cell in the maze
		int originx = s.spacing + x * s.scale;
		int originy = s.spacing + y * s.scale;
		s.strokeWeight(2);   // Thicker
		s.stroke(0); //draw with black
		s.fill(0); //fill with black
		if(northWall && southWall && eastWall && westWall){
			//if cell is unvisited, draw a solid light-grey block
			s.rect(originx, originy, s.scale, s.scale);
		} else {
			//if visited, draw intact walls
			if (northWall && !start) s.line(originx, originy, originx + s.scale, originy);
			if (southWall && !end)   s.line(originx, originy + s.scale, originx + s.scale, originy + s.scale);
			if (eastWall)            s.line(originx + s.scale, originy, originx + s.scale, originy + s.scale);
			if (westWall)            s.line(originx, originy, originx, originy + s.scale);
		}
	}
	public void drawCellPath(Sketch s){
		int originx = s.spacing + x * s.scale;
		int originy = s.spacing + y * s.scale;
		s.stroke(0,255,143);
		s.fill(0,255,143);
		s.rect(originx+4, originy+4, s.scale-8, s.scale-8);
	}
	//mark cell
	public void markCell(Sketch s){
		//calculate origin (top-left corner) of this cell in the maze
		int originx = s.spacing + x * s.scale;
		int originy = s.spacing + y * s.scale;
		s.stroke(245,184,0);
		s.fill(245,184,0);
		
		if(isStart()) 
			s.rect(originx+2, originy+2, s.scale-5, s.scale-5);
	}
	//mark end
	//mark cell
		public void markEnd(Sketch s){
			//calculate origin (top-left corner) of this cell in the maze
			int originx = s.spacing + x * s.scale;
			int originy = s.spacing + y * s.scale;
			s.stroke(0,0,255);
			s.fill(0,0,255);
			
			if(isEnd()) 
				s.rect(originx+2, originy+2, s.scale-5, s.scale-5);
		}
	
}
